package nl.ru.rd.facedetection.nnbfd;

import nl.ru.rd.facedetection.nnbfd.neuralnetwork.BMLayer;
import nl.ru.rd.facedetection.nnbfd.neuralnetwork.BNLayer;
import nl.ru.rd.facedetection.nnbfd.neuralnetwork.Input;
import nl.ru.rd.facedetection.nnbfd.neuralnetwork.InputLayer;
import nl.ru.rd.facedetection.nnbfd.neuralnetwork.NeuralNetwork;
import nl.ru.rd.facedetection.nnbfd.neuralnetwork.SigmoidActivationfunction;

/**
 * A Neural Network used for FaceDetection as described by Rowley et al.
 * 
 * @author Wouter Geraedts (s0814857 - wgeraedts) PGP 66AA5935
 */
public class FacedetectionNetwork extends NeuralNetwork
{
	private static final long serialVersionUID = 8377722078236483437L;

	/**
	 * Constructs a Neural Network used for FaceDetection as described by Rowley et al.
	 */
	public FacedetectionNetwork()
	{
		super();
		this.initialize();
	}

	private void initialize()
	{
		Input[][] inputs = new Input[20][20];

		for(int i = 0; i < inputs.length; i++)
			for(int j = 0; j < inputs[i].length; j++)
			{
				inputs[i][j] = new Input(0.0);
				this.registerInput(inputs[i][j]);
			}

		final SigmoidActivationfunction f = new SigmoidActivationfunction();
		final int blockNumber = 4 + 16 + 6;
		BNLayer[] blockLayers = new BNLayer[blockNumber];

		for(int i = 0; i < 2; i++)
			for(int j = 0; j < 2; j++)
			{
				InputLayer inputLayer = new InputLayer();

				int xOffset = i * 10;
				int yOffset = j * 10;

				for(int x = xOffset; x < 10 + xOffset; x++)
					for(int y = yOffset; y < 10 + yOffset; y++)
						inputLayer.addInput(inputs[x][y]);

				this.registerLayer(inputLayer);

				blockLayers[i * 2 + j] = new BNLayer(inputLayer, 1, f);
			}

		for(int i = 0; i < 4; i++)
			for(int j = 0; j < 4; j++)
			{
				InputLayer inputLayer = new InputLayer();

				int xOffset = i * 5;
				int yOffset = j * 5;

				for(int x = xOffset; x < 5 + xOffset; x++)
					for(int y = yOffset; y < 5 + yOffset; y++)
						inputLayer.addInput(inputs[x][y]);

				this.registerLayer(inputLayer);

				blockLayers[4 + (i * 4 + j)] = new BNLayer(inputLayer, 1, f);
			}

		for(int i = 0; i < 1; i++)
			for(int j = 0; j < 6; j++)
			{
				InputLayer inputLayer = new InputLayer();

				int xOffset = i * 0;
				int yOffset = j * 3;

				for(int x = xOffset; x < 20 + xOffset; x++)
					for(int y = yOffset; y < 5 + yOffset; y++)
						inputLayer.addInput(inputs[x][y]);

				this.registerLayer(inputLayer);

				blockLayers[20 + (i + j)] = new BNLayer(inputLayer, 1, f);
			}

		for(int i = 0; i < blockLayers.length; i++)
			this.registerLayer(blockLayers[i]);

		BMLayer outputLayer = new BMLayer(blockLayers, 1, f);
		this.registerLayer(outputLayer);
		this.registerOutputLayer(outputLayer);
	}
}